/*
 * Copyright 2011 Clean GWT
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.cleangwt.showcase.client.page;

import java.util.List;

import com.cleangwt.bootstrap.client.style.Btn;
import com.cleangwt.bootstrap.client.ui.Alert;
import com.cleangwt.bootstrap.client.ui.GroupFormPanel;
import com.cleangwt.bootstrap.client.ui.Modal;
import com.cleangwt.bootstrap.client.ui.RadioField;
import com.cleangwt.bootstrap.support.client.TooltipErrorHandler;
import com.cleangwt.json.client.SimpleObject;
import com.cleangwt.page.client.PageContext.CodeSplit;
import com.cleangwt.page.client.PageContext.Page;
import com.cleangwt.page.client.PageContext.Prefetch;
import com.cleangwt.showcase.client.ProvidesSource;
import com.cleangwt.showcase.client.component.InterestingCell;
import com.cleangwt.showcase.client.component.ShowcasePage;
import com.cleangwt.showcase.client.resource.DataSource;
import com.cleangwt.showcase.client.resource.PageGroups;
import com.cleangwt.showcase.client.resource.i18n.DynamicValidatorMessages;
import com.cleangwt.showcase.client.resource.i18n.ShowcaseMessages;
import com.cleangwt.user.cellview.client.ActionColumn;
import com.cleangwt.user.cellview.client.ActionColumn.TableActionHandler;
import com.cleangwt.user.cellview.client.DataColumn;
import com.cleangwt.user.cellview.client.DataGrid;
import com.cleangwt.user.cellview.client.NumberColumn;
import com.cleangwt.user.cellview.client.TextColumn;
import com.cleangwt.user.client.ui.Button;
import com.cleangwt.user.client.ui.Lay;
import com.cleangwt.user.client.ui.NumberBox;
import com.cleangwt.user.client.ui.TextBox;
import com.cleangwt.validation.client.Validation;
import com.cleangwt.validation.client.Validator;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SingleSelectionModel;

/**
 * @author Jess
 * @version 1.0
 * @since 1.0
 */
@Prefetch(PageGroups.VALIDATION)
@CodeSplit
@Page
public class DynamicValidationDemo extends ShowcasePage implements ClickHandler, ProvidesSource {

  Button btnAdd;
  Button btnVerify;
  DynamicValidatorMessages c;
  DataGrid dataGrid;
  Validator listValidator;
  NumberBox numfSalary;

  RadioField radfMale;
  ListDataProvider<SimpleObject> tableData;
  TextBox txtfName;
  Validator userValidator;

  public DynamicValidationDemo() {
    super(ShowcaseMessages.Impl.dynamicvalidation(),
        "Without constraint annotaions, validation can also be bound dynamically.",
        "DynamicValidationDemo.java");
    c = GWT.create(DynamicValidatorMessages.class);
    txtfName = new TextBox();
    radfMale = new RadioField(true);
    numfSalary = new NumberBox(3);
    btnAdd = new Button(c.add());
    btnVerify = new Button(c.verify());
    dataGrid = new DataGrid(10);
    tableData = new ListDataProvider<SimpleObject>();
    GroupFormPanel userForm = new GroupFormPanel();

    userValidator = new Validator(new TooltipErrorHandler());
    listValidator = new Validator(new TooltipErrorHandler());

    setContentWidget(userForm);

    userForm.build().add(c.name(), txtfName).div(4).add(c.salary(), numfSalary).div(4).add(c.sex(),
        radfMale).div(4);
    userForm.add(Lay.pullRight(Lay.p(Btn.style(btnAdd))));
    userForm.add(dataGrid);
    userForm.add(Lay.pullRight(Btn.primary(btnVerify)));

    dataGrid.addColumn(new TextColumn("name"), c.name());
    dataGrid.addColumn(new TextColumn("male"), c.sex());
    dataGrid.addColumn(new DataColumn<List<String>>("interesting", new InterestingCell(DataSource
        .getInterestings2()), false, true), c.interesting());
    dataGrid.addColumn(new NumberColumn("salary"), c.salary());
    dataGrid.addColumn(new ActionColumn(c.delete(), new TableActionHandler() {

      @Override
      public void onTableAction(String action, int index, SimpleObject gridData) {
        tableData.getList().remove(gridData);
      }
    }), c.delete());

    dataGrid.setSelectionModel(new SingleSelectionModel<SimpleObject>(),
        DefaultSelectionEventManager.<SimpleObject> createWhitelistManager(-1));
    dataGrid.setEmptyTableWidget(null);
    dataGrid.setSize("100%", "280px");

    dataGrid.setColumnWidth(2, "200px");

    tableData.addDataDisplay(dataGrid);

    radfMale.setOptions(DataSource.getSexTypes());

    btnAdd.addClickHandler(this);
    btnVerify.addClickHandler(this);

    bindValiator();
  }

  void addUser(SimpleObject newUser) {
    tableData.getList().add(getNewUser());
    //
    txtfName.setValue(null);
    radfMale.setValue(null);
    numfSalary.setValue(null);
  }

  private void bindValiator() {
    userValidator.build(txtfName).notNull();
    userValidator.build(numfSalary).add(new Validation() {

      @Override
      public String validate(Object[] values) {
        if (numfSalary.getValue() == null) {
          return "Required!!";
        } else if (numfSalary.getValue().intValue() > 1000000) {
          return "Salary can not over 1,000,000";
        }
        return null;
      }
    });

    listValidator.addValidation(new Validation() {

      @Override
      protected String validate(Object[] values) {
        List<SimpleObject> users = tableData.getList();
        for (SimpleObject user : users) {
          @SuppressWarnings("unchecked")
          List<String> interestings = (List<String>) user.get("interesting");
          dataGrid.getSelectionModel().setSelected(user, false);
          if (interestings == null || interestings.size() == 0
              || (interestings.size() == 2 && interestings.get(0).equals(interestings.get(1)))) {
            dataGrid.getSelectionModel().setSelected(user, true);
            return c.interestingError();
          } else if (getTotalSalary() > 1000000) {
            return c.salaryConstraints(1000000);
          }
        }
        return null;
      }
    });

    userValidator.activate();
    listValidator.activate();
  }

  SimpleObject getNewUser() {
    SimpleObject user = new SimpleObject();
    user.put("name", txtfName.getValue());
    user.put("male", radfMale.getValue());
    user.put("salary", numfSalary.getValue());
    return user;
  }

  private long getTotalSalary() {
    List<SimpleObject> users = tableData.getList();
    long total = 0;

    for (SimpleObject user : users) {
      total += user.get("salary") == null ? 0 : ((Number) user.get("salary")).intValue();
    }
    return total;
  }

  @Override
  public void onClick(ClickEvent event) {
    if (event.getSource() == btnAdd) {
      if (userValidator.validate()) {
        addUser(getNewUser());
        userValidator.reset();
      }
    } else if (event.getSource() == btnVerify) {
      if (listValidator.validate()) {
        Alert.alert(c.valid());
      } else {
        Modal.message(listValidator.getValidationErrors(false).get(0).getMessage());
      }
    }
  }

}
